package org.codeanalyzer;

import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

import org.codeanalyzer.model.ApiLibrary;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.TreeInfo;

public class UsageAnalyzerTreeVisitor extends TreePathScanner<Object, Trees>
{

    private final ApiLibrary apiLibrary;
    public CompilationUnitTree compilationUnit;

    public UsageAnalyzerTreeVisitor(ApiLibrary apiLibrary)
    {
        this.apiLibrary = apiLibrary;
    }

    @Override
    public Object visitMethodInvocation(MethodInvocationTree node, Trees p)
    {
        // JCMethodInvocation jcMethodInvocation = (JCMethodInvocation)node;

        // if (jcMethodInvocation.getMethodSelect() instanceof JCIdent)
        // {
        // JCIdent methodSelect = (JCIdent)jcMethodInvocation.getMethodSelect();
        // //System.out.println("methodSelect = " + methodSelect.toString());
        // }
        // else if (jcMethodInvocation.getMethodSelect() instanceof JCFieldAccess)
        // {
        // JCFieldAccess fieldAccess = (JCFieldAccess)jcMethodInvocation.getMethodSelect();
        // JCExpression expression = fieldAccess.getExpression();
        // System.out.println("fieldAccess = " + fieldAccess.toString() + ", expression = " + expression.toString());
        // }

        // TODO Add case method(Object ...)
        // TODO Add generics

        JCTree methodSelect = (JCTree)node.getMethodSelect();
        Element method = TreeInfo.symbol(methodSelect);
        if (method != null && method.getEnclosingElement() instanceof TypeElement)
        {
            // remove redundant generic symbols
            String methodNameWithParameters = method.toString().replaceFirst("<.*?>", "");
            if (methodNameWithParameters.startsWith("<"))
                methodNameWithParameters = methodNameWithParameters.replaceFirst("<.*?>", "");

            TypeElement invokedClass = (TypeElement)method.getEnclosingElement();
            String invokedClassFullName = invokedClass.toString();

            // DiagnosticPosition pos = methodSelect.pos();
            // System.out.println(String.format("invokedMethod=%s.%-30s [%s]",
            // invokedClassFullName, methodNameWithParameters, pos));

            apiLibrary.addMethodCoverage(invokedClassFullName, methodNameWithParameters);
        }

        return super.visitMethodInvocation(node, p);
    }

    @Override
    public Object visitNewClass(NewClassTree node, Trees p) {
        // System.out.println("Visit new class " + node);

        JCTree identifier = (JCTree)node.getIdentifier();

        String className = TreeInfo.symbol(identifier).toString();
        String constructorNameWithParameters = ((JCNewClass)node).constructor.toString();

        apiLibrary.addMethodCoverage(className, constructorNameWithParameters);

        return super.visitNewClass(node, p);
    }


    // **************************************************************************************
    // Support methods
    // **************************************************************************************

}
